package net.stogi.unicore.beyond.ui.client.taskrunner.taskinstance;

import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import net.stogi.common.mvp.core.behavior.Behavior;
import net.stogi.unicore.beyond.api.model.InputDefinition;
import net.stogi.unicore.beyond.api.model.OutputDefinition;
import net.stogi.unicore.beyond.io.client.input.combofield.ComboInputField;
import net.stogi.unicore.beyond.io.client.input.core.InputField;
import net.stogi.unicore.beyond.io.client.input.datefield.DateInputField;
import net.stogi.unicore.beyond.io.client.input.doublefield.DoubleInputField;
import net.stogi.unicore.beyond.io.client.input.integerfield.IntegerInputField;
import net.stogi.unicore.beyond.io.client.input.richtextfield.RichTextInputField;
import net.stogi.unicore.beyond.io.client.input.textfield.TextInputField;
import net.stogi.unicore.beyond.io.client.output.appletviewfield.AppletViewOutputField;
import net.stogi.unicore.beyond.io.client.output.core.OutputField;
import net.stogi.unicore.beyond.io.client.output.filedownloadfield.FileDownloadOutputField;
import net.stogi.unicore.beyond.io.client.output.imageviewfield.ImageViewOutputField;

import com.extjs.gxt.ui.client.event.ButtonEvent;
import com.extjs.gxt.ui.client.event.SelectionListener;
import com.extjs.gxt.ui.client.widget.Component;
import com.extjs.gxt.ui.client.widget.Composite;
import com.extjs.gxt.ui.client.widget.ContentPanel;
import com.extjs.gxt.ui.client.widget.TabItem;
import com.extjs.gxt.ui.client.widget.TabPanel;
import com.extjs.gxt.ui.client.widget.Window;
import com.extjs.gxt.ui.client.widget.button.Button;
import com.extjs.gxt.ui.client.widget.form.FormPanel;
import com.extjs.gxt.ui.client.widget.form.TextArea;
import com.extjs.gxt.ui.client.widget.form.TextField;
import com.extjs.gxt.ui.client.widget.layout.CardLayout;
import com.extjs.gxt.ui.client.widget.layout.FitData;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.extjs.gxt.ui.client.widget.layout.FormData;
import com.extjs.gxt.ui.client.widget.toolbar.ToolBar;
import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.ui.Widget;

class TaskInstanceWidget extends Widget implements TaskInstanceView {

	private class MainSectionPanel extends Composite {

		private final TextArea applicationDescTextArea = new TextArea();

		private final TextField<String> applicationNameTextField = new TextField<String>();

		private final TextField<String> applicationVersionTextField = new TextField<String>();

		private final FormPanel mainPanel = new FormPanel();

		public MainSectionPanel() {
			initComposite();
			initI18n();
			initLayout();
			initComponent(mainPanel);
		}

		private void initComposite() {
			applicationDescTextArea.setEnabled(false);
			applicationNameTextField.setEnabled(false);
			applicationVersionTextField.setEnabled(false);
			mainPanel.setBodyBorder(false);
			mainPanel.setHeaderVisible(false);
			mainPanel.setLabelSeparator("");
			mainPanel.setLabelWidth(120);
		}

		private void initI18n() {
			applicationNameTextField.setFieldLabel("Name");
			applicationVersionTextField.setFieldLabel("Version");
			applicationDescTextArea.setFieldLabel("Description");
		}

		private void initLayout() {
			mainPanel.add(applicationNameTextField, DEFAULT_FORM_DATA);
			mainPanel.add(applicationVersionTextField, DEFAULT_FORM_DATA);
			mainPanel.add(applicationDescTextArea, DEFAULT_FORM_DATA);
		}
	}

	private final static FormData DEFAULT_FORM_DATA = new FormData("-22");

	private final Button closeButton = new Button();
	
	private Map<String, InputField> inputs = new HashMap<String, InputField>();

	private final Button inputSectionButton = new Button();

	private final TabPanel inputSectionPanel = new TabPanel();

	private final ContentPanel mainPanel = new ContentPanel();

	private final CardLayout mainPanelLayout = new CardLayout();

	private final Button mainSectionButton = new Button();

	private final MainSectionPanel mainSectionPanel = new MainSectionPanel();

	private final ToolBar mainToolBar = new ToolBar();

	private final Window mainWindow = new Window();

	private final Button outputSectionButton = new Button();

	private final TabPanel outputSectionPanel = new TabPanel();
	
	private final Button runButton = new Button();

	public TaskInstanceWidget() {
		initComposite();
		initHandlers();
		initI18n();
		initLayout();
	}

	@Override
	public int addInputDefinition(InputDefinition inputDefinition, int inputGroupIndex) {
		assert inputDefinition != null;
		assert inputGroupIndex > -1;
		final InputField inputField = doCreateInputFieldInstance(inputDefinition);
		TabItem tabItem = inputSectionPanel.getItem(inputGroupIndex);
		if (tabItem != null) {
			FormPanel panel = (FormPanel) tabItem.getWidget(0);
			if (panel.add(inputField.asWidget(), DEFAULT_FORM_DATA)) {
				inputs.put(inputDefinition.getName(), inputField);
				return tabItem.getItemCount() - 1;
			}
		}
		GWT.log("Could not add new input definition");
		return -1;
	}

	@Override
	public int addInputGroup(String name) {
		assert name != null;
		TabItem tabItem = doCreateGroupTabItem(name);
		if (inputSectionPanel.add(tabItem)) {
			return inputSectionPanel.getItemCount() - 1;
		}
		GWT.log("Could not add new input group");
		return -1;
	}

	@Override
	public int addOutputDefinition(OutputDefinition outputDefinition, int outputGroupIndex) {
		assert outputDefinition != null;
		assert outputGroupIndex > -1;
		final OutputField outputField = doCreateOutputFieldInstance(outputDefinition);
		TabItem tabItem = outputSectionPanel.getItem(outputGroupIndex);
		if (tabItem != null) {
			FormPanel panel = (FormPanel) tabItem.getWidget(0);
			if (panel.add(outputField.asWidget(), DEFAULT_FORM_DATA)) {
				return tabItem.getItemCount() - 1;
			}
		}
		GWT.log("Could not add new input definition");
		return -1;
	}

	@Override
	public int addOutputGroup(String name) {
		assert name != null;
		TabItem tabItem = doCreateGroupTabItem(name);
		if (outputSectionPanel.add(tabItem)) {
			return outputSectionPanel.getItemCount() - 1;
		}
		GWT.log("Could not add new output group");
		return -1;
	}

	@Override
	public void appear() {
		mainWindow.show();
	}

	@Override
	public void clear() {
		inputSectionPanel.removeAll();
		outputSectionPanel.removeAll();
		mainSectionPanel.applicationDescTextArea.setRawValue(null);
		mainSectionPanel.applicationNameTextField.setRawValue(null);
		mainSectionPanel.applicationVersionTextField.setRawValue(null);
		mainPanelLayout.setActiveItem(mainSectionPanel);
		mainWindow.layout(true);
	}

	@Override
	public void clearErrors() {
		for (InputField input : inputs.values()) {
			input.setError(null);
		}
	}

	@Override
	public Map<String, String> collectInputs() {
		Map<String, String> inputs = new HashMap<String, String>();
		for (Entry<String, InputField> entry : this.inputs.entrySet()) {
			inputs.put(entry.getKey(), entry.getValue().getValue());
		}
		return inputs;
	}

	@Override
	public void disappear() {
		mainWindow.hide();
		clear();
	}

	@Override
	public void displayApplicationDescription(String applicationDescription) {
		mainSectionPanel.applicationDescTextArea.setValue(applicationDescription);
	}

	@Override
	public void displayApplicationName(String applicationName) {
		mainSectionPanel.applicationNameTextField.setValue(applicationName);
	}

	@Override
	public void displayApplicationVersion(String applicationVersion) {
		mainSectionPanel.applicationVersionTextField.setValue(applicationVersion);
	}

	@Override
	public void layout() {
		mainWindow.layout(true);
	}

	@Override
	public void setCloseBehavior(final Behavior behavior) {
		closeButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
			
			@Override
			public void componentSelected(ButtonEvent ce) {
				behavior.behave();
			}
		});
	}

	@Override
	public void setErrors(Map<String, String> errors) {
		for (Entry<String, String> error : errors.entrySet()) {
			inputs.get(error.getKey()).setError(error.getValue());
		}
	}

	@Override
	public void setRunBehavior(final Behavior behavior) {
		runButton.addSelectionListener(new SelectionListener<ButtonEvent>() {
			
			@Override
			public void componentSelected(ButtonEvent ce) {
				behavior.behave();
			}
		});
	}

	private TabItem doCreateGroupTabItem(String name) {
		final FormPanel panel = new FormPanel();
		panel.setBodyBorder(false);
		panel.setHeaderVisible(false);
		panel.setLabelSeparator("");
		final TabItem tabItem = new TabItem(name);
		tabItem.setLayout(new FitLayout());
		tabItem.add(panel, new FitData());
		return tabItem;
	}

	private InputField doCreateInputFieldInstance(InputDefinition inputDefinition) {
		InputField inputField = null;

		String inputTypeName = inputDefinition.getInputType().getName();
		// Create text field.
		if ("textfield".equals(inputTypeName)) {
			inputField = new TextInputField(inputDefinition);
		}
		// Create rich text field.
		else if ("richtextfield".equals(inputTypeName)) {
			inputField = new RichTextInputField(inputDefinition);
		}
		// Create integer field.
		else if ("integerfield".equals(inputTypeName)) {
			inputField = new IntegerInputField(inputDefinition);
		}
		// Create double field.
		else if ("doublefield".equals(inputTypeName)) {
			inputField = new DoubleInputField(inputDefinition);
		}
		// Create date field.
		else if ("datefield".equals(inputTypeName)) {
			inputField = new DateInputField(inputDefinition);
		}
		// Create combo field.
		else if ("combofield".equals(inputTypeName)) {
			inputField = new ComboInputField(inputDefinition);
		}

		return inputField;
	}

	private OutputField doCreateOutputFieldInstance(OutputDefinition outputDefinition) {
		OutputField outputField = null;

		String outputTypeName = outputDefinition.getOutputType().getName();
		// Create file download field.
		if ("filedownloadfield".equals(outputTypeName)) {
			outputField = new FileDownloadOutputField(outputDefinition);
		}
		// Create image viewer field.
		else if ("imageviewfield".equals(outputTypeName)) {
			outputField = new ImageViewOutputField(outputDefinition);
		}
		// Create applet viewer field.
		else if ("appletviewfield".equals(outputTypeName)) {
			outputField = new AppletViewOutputField(outputDefinition);
		}

		return outputField;
	}

	private void doInitComponentButtonHandler(final Component component, Button button) {
		button.addSelectionListener(new SelectionListener<ButtonEvent>() {

			@Override
			public void componentSelected(ButtonEvent ce) {
				mainPanelLayout.setActiveItem(component);
			}
		});
	}
	
	private void doInitIoTabPanel(TabPanel panel) {
		panel.setResizeTabs(true);
		panel.setAnimScroll(true);
		panel.setTabScroll(true);
		panel.setBodyBorder(false);
		panel.setMinTabWidth(130);
	}
	
	private void initComposite() {
		doInitIoTabPanel(inputSectionPanel);
		doInitIoTabPanel(outputSectionPanel);

		mainPanel.setBodyBorder(false);
		mainPanel.setHeaderVisible(false);
		mainPanel.setLayout(mainPanelLayout);

		mainWindow.setClosable(false);
		mainWindow.setHeight("600px");
		mainWindow.setFrame(true);
		mainWindow.setResizable(false);
		mainWindow.setWidth("50%");
		mainWindow.setLayout(new FitLayout());
	}

	private void initHandlers() {
		doInitComponentButtonHandler(inputSectionPanel, inputSectionButton);
		doInitComponentButtonHandler(mainSectionPanel, mainSectionButton);
		doInitComponentButtonHandler(outputSectionPanel, outputSectionButton);
	}

	private void initI18n() {
		mainWindow.setHeading("Task Instance");
		mainSectionButton.setText("Main");
		inputSectionButton.setText("Inputs");
		outputSectionButton.setText("Outputs");
		closeButton.setText("Close");
		runButton.setText("Run");
	}
	
	private void initLayout() {
		mainToolBar.add(mainSectionButton);
		mainToolBar.add(inputSectionButton);
		mainToolBar.add(outputSectionButton);
		mainPanel.setTopComponent(mainToolBar);
		mainPanel.add(mainSectionPanel);
		mainPanel.add(inputSectionPanel);
		mainPanel.add(outputSectionPanel);
		mainWindow.add(mainPanel);
		mainWindow.addButton(runButton);
		mainWindow.addButton(closeButton);
	}
}
